#include "RtBase.h"
#include "RtTimerWrapper.h"
#include "RtTimerQueueCalendar.h"
#include "RtConditionVariable.h"

#include "RtTimerPreciseWrapperID.h"

//////////////////////////////////////////////////////////////////////
// class CRtTimerPreciseManager
//////////////////////////////////////////////////////////////////////
static CRtTimerPreciseManager* s_pPreciseTimerMgr = NULL;

CRtTimerPreciseManager::CRtTimerPreciseManager()
{
	m_pTimerQueue = new CRtTimerQueueCalendar(10,1000*60*60*2,NULL);

	RT_ASSERTE( m_pTimerQueue );

	//call parent function,delele self by thread manager since register self.
	CRtThread::Create(CRtThreadManager::TT_TIMER, CRtThreadManager::TF_JOINABLE);
}

CRtTimerPreciseManager::~CRtTimerPreciseManager()
{
	if( m_pTimerQueue )
	{
		delete m_pTimerQueue;
		m_pTimerQueue = NULL;
	}
}

CRtTimerPreciseManager* CRtTimerPreciseManager::Instance()
{
	if( !s_pPreciseTimerMgr )
		s_pPreciseTimerMgr = new CRtTimerPreciseManager();

	return s_pPreciseTimerMgr;
}

RtResult CRtTimerPreciseManager::Schedule(
		CRtTimerPreciseWrapperID* aTimerId,
		CRtTimerPreciseWrapperIDSink* aSink,
		const CRtTimeValue &aInterval,
		DWORD aCount)
{
	RT_ASSERTE( aTimerId );
	if( m_pTimerQueue )
	{
		CRtMutexGuardT<CRtMutexThread> theGuard(m_Mutex);
		m_pTimerQueue->ScheduleTimer(aTimerId,aSink,aInterval,aCount);
	}

	return RT_OK;
}

RtResult CRtTimerPreciseManager::Cancel(CRtTimerPreciseWrapperID* aTimerId)
{
	RtResult rv = RT_ERROR_NULL_POINTER;
	if (aTimerId && m_pTimerQueue)
	{
		CRtMutexGuardT<CRtMutexThread> theGuard(m_Mutex);

		rv = m_pTimerQueue->CancelTimer( aTimerId );
	}

	return rv;
}

void CRtTimerPreciseManager::OnThreadInit()
{
	m_pTimerQueue->m_Est.Reset2CurrentThreadId();
	
	CRtStopFlag::m_Est.Reset2CurrentThreadId();
	SetStartFlag();
}

void CRtTimerPreciseManager::OnThreadRun()
{
	CRtEventThread Event;
	CRtTimeValue tv(0,10000);
	while (!IsFlagStopped()) 
	{
		Event.Wait(&tv);
		CRtMutexGuardT<CRtMutexThread> theGuard(m_Mutex);

		m_pTimerQueue->TimerTick();
	}
}

RtResult CRtTimerPreciseManager::Stop(CRtTimeValue* aTimeout )
{
	SetStopFlag();
	return RT_OK;
}


//////////////////////////////////////////////////////////////////////
// class CRtTimerPreciseWrapperID
//////////////////////////////////////////////////////////////////////
CRtTimerPreciseWrapperID::CRtTimerPreciseWrapperID()
	: m_bScheduled(FALSE)
	, m_TType(CRtThreadManager::TT_UNKNOWN)
	, m_pThread( NULL )
	, m_pEventQueue( NULL)
{
	CRtTimerPreciseManager::Instance();
	RT_ASSERTE( s_pPreciseTimerMgr );
}

CRtTimerPreciseWrapperID::~CRtTimerPreciseWrapperID()
{
	Cancel();
}

RtResult CRtTimerPreciseWrapperID::Schedule(
		CRtTimerPreciseWrapperIDSink* aSink,
		const CRtTimeValue &aInterval,
		DWORD aCount,
		CRtThreadManager::TType aTType)
{
	if( aTType == CRtThreadManager::TT_CURRENT ||
		aTType == CRtThreadManager::TT_TIMER)
		return RT_ERROR_INVALID_ARG;
	
	m_TType = aTType;
	m_pThread = CRtThreadManager::Instance()->GetThread(m_TType);
	RT_ASSERTE( m_pThread );
	if( !m_pThread )
		return RT_ERROR_NULL_POINTER;

	m_pEventQueue = m_pThread->GetEventQueue();
	RT_ASSERTE( m_pEventQueue );
	if( !m_pEventQueue )
		return RT_ERROR_NULL_POINTER;

	if( !s_pPreciseTimerMgr )
		return RT_ERROR_NULL_POINTER;

	s_pPreciseTimerMgr->Schedule(this,aSink,aInterval,aCount);

	m_bScheduled = TRUE;

	return RT_OK;
}

RtResult CRtTimerPreciseWrapperID::Cancel()
{
	if (!m_bScheduled)
		return RT_ERROR_FAILURE;

	if( !s_pPreciseTimerMgr )
		return RT_ERROR_NULL_POINTER;

	s_pPreciseTimerMgr->Cancel(this);

	m_bScheduled = FALSE;
	
	return RT_OK;
}

void CRtTimerPreciseWrapperID::OnTimeout(const CRtTimeValue &aCurTime, LPVOID aArg)
{
	RT_ASSERTE(m_bScheduled);
	if( !m_bScheduled)
		return;
	
	CRtTimerPreciseWrapperIDSink *pSink = static_cast<CRtTimerPreciseWrapperIDSink *>(aArg);
	RT_ASSERTE(pSink);
	if( pSink && m_pEventQueue )
	{
		CEventTimer *pEvent = new CEventTimer( pSink,this );
		m_pEventQueue->PostEvent(pEvent);
	}
}

//////////////////////////////////////////////////////////////////////
// class CEventTimer
//////////////////////////////////////////////////////////////////////
CEventTimer::CEventTimer(CRtTimerPreciseWrapperIDSink *pSink, CRtTimerPreciseWrapperID* pTimerId)
	:m_pSink( pSink )
	,m_pTimerId( pTimerId )
{
}

CEventTimer::~CEventTimer()
{
}

RtResult CEventTimer::OnEventFire()
{
	if( m_pTimerId->GetStatus() )
		m_pSink->OnTimer( m_pTimerId );

	return RT_OK;
}
